package com.godfrey.poi.controller;

import com.godfrey.poi.pojo.*;
import com.godfrey.poi.service.PoiService;
import com.godfrey.poi.util.ExcelUtil;
import de.felixroske.jfxsupport.FXMLController;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.MouseEvent;
import javafx.util.StringConverter;

import javax.annotation.Resource;
import java.net.URL;
import java.util.List;
import java.util.ResourceBundle;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author godfrey
 * @since 2021-12-05
 */
@FXMLController
public class PoiController implements Initializable {

    /**
     * 关键词
     */
    @FXML
    private TextField keywords;


    /**
     * 消息框
     */
    @FXML
    private TextArea messageDetail;

    /**
     * 线程数
     */
    @FXML
    public ChoiceBox<String> threadNum;

    /**
     * 省份
     */
    @FXML
    private ChoiceBox<District> provincesBox;

    /**
     * 城市
     */
    @FXML
    private ChoiceBox<District> cityBox;

    /**
     * 区县
     */
    @FXML
    private ChoiceBox<District> countyBox;

    /**
     * 乡镇
     */
    @FXML
    private ChoiceBox<District> streetBox;

    /**
     * 行业大类
     */
    @FXML
    private ChoiceBox<String> bigCategoryBox;

    /**
     * 行业中类
     */
    @FXML
    private ChoiceBox<String> midCategoryBox;

    /**
     * 行业小类
     */
    @FXML
    private ChoiceBox<String> subCategoryBox;

    /**
     * Poi表格
     */
    @FXML
    public TableView<Poi> tableView;

    /**
     * 序号
     */
    @FXML
    private TableColumn<Poi, Integer> colNum;

    /**
     * 名称
     */
    @FXML
    private TableColumn<Poi, String> colName;

    /**
     * POI所在省份名称
     */
    @FXML
    private TableColumn<Poi, String> colPname;

    /**
     * 城市名
     */
    @FXML
    private TableColumn<Poi, String> colCityname;

    /**
     * 区域名称
     */
    @FXML
    private TableColumn<Poi, String> colAdname;

    /**
     * 地址
     */
    @FXML
    private TableColumn<Poi, String> colAddress;

    /**
     * 别名
     */
    @FXML
    private TableColumn<Poi, String> colAlias;

    /**
     * POI的电话
     */
    @FXML
    private TableColumn<Poi, String> colTel;

    /**
     * 经纬度
     */
    @FXML
    private TableColumn<Poi, String> colLocation;

    /**
     * 唯一ID
     */
    @FXML
    private TableColumn<Poi, String> colId;

    /**
     * 该POI的特色内容
     */
    @FXML
    private TableColumn<Poi, String> colTag;

    /**
     * POI所在省份编码
     */
    @FXML
    private TableColumn<Poi, String> colPcode;

    /**
     * 兴趣点类型
     */
    @FXML
    private TableColumn<Poi, String> colType;

    /**
     * 兴趣点类型编码
     */
    @FXML
    private TableColumn<Poi, String> colTypecode;

    /**
     * 城市编码
     */
    @FXML
    private TableColumn<Poi, String> colCitycode;

    /**
     * POI的网址
     */
    @FXML
    private TableColumn<Poi, String> colWebsite;

    /**
     * POI的电子邮箱
     */
    @FXML
    private TableColumn<Poi, String> colEmail;

    /**
     * 区域编码
     */
    @FXML
    private TableColumn<Poi, String> colAdcode;

    /**
     * 地理格ID
     */
    @FXML
    private TableColumn<Poi, String> colGridcode;

    /**
     * POI的入口经纬度
     */
    @FXML
    private TableColumn<Poi, String> colEntrLocation;

    /**
     * POI的出口经纬度
     */
    @FXML
    private TableColumn<Poi, String> colExitLocation;

    /**
     * POI数据转换
     */
    private final StringConverter<District> converter = new StringConverter<District>() {
        //只显示名字
        @Override
        public String toString(District district) {
            return district.getName();
        }

        @Override
        public District fromString(String string) {
            return null;
        }
    };

    @Resource
    private PoiService poiService;

    /**
     * POI行业分类编码
     */
    private List<PoiCategory> poiCategoryList = null;

    /**
     * 全国街道数据
     */
    private List<Street> streetList = null;

    /**
     * 初始化
     */
    @Override
    public void initialize(URL location, ResourceBundle resources) {

        //读取Excel获取POI行业编码
        poiCategoryList = ExcelUtil.excelToList("doc/poicode.xlsx", "POI分类编码表", PoiCategory.class);
        //读取Excel获取全国街道数据
        streetList = ExcelUtil.excelToList("doc/street.xlsx", "街道数据表", Street.class);
        //初始化行业大类
        List<String> bigCategoryList = poiCategoryList.stream().map(PoiCategory::getBigCategory).distinct().collect(Collectors.toList());
        //行业大类下拉列表
        bigCategoryBox.getItems().addAll(bigCategoryList);

        //100000是中国，初始化省份List
        List<District> provincesList = poiService.searchNextDistrict("100000");
        //数据转换
        provincesBox.setConverter(converter);
        //省份下拉列表
        provincesBox.getItems().addAll(provincesList);
    }

    /**
     * 查询POI行业分类
     *
     * @param mouseEvent 鼠标点击事件
     * @return void
     */
    public void searchCategory(MouseEvent mouseEvent) {
        if (bigCategoryBox.equals(mouseEvent.getSource())) {
            midCategoryBox.setValue(null);
            subCategoryBox.setValue(null);
        } else if (midCategoryBox.equals(mouseEvent.getSource())) {
            if (null == bigCategoryBox.getValue()) {
                messageTip("请先选择行业大类");
                return;
            }
            List<String> midCategoryList = poiCategoryList.stream().filter(e -> e.getBigCategory().equals(bigCategoryBox.getValue())).map(PoiCategory::getMidCategory).distinct().collect(Collectors.toList());
            midCategoryBox.getItems().remove(0, midCategoryBox.getItems().size());
            midCategoryBox.getItems().addAll(midCategoryList);
            subCategoryBox.setValue(null);
            midCategoryBox.show();
        } else {
            if (null == midCategoryBox.getValue()) {
                messageTip("请先选择行业中类");
                return;
            }
            List<String> subCategoryList = poiCategoryList.stream().filter(e -> e.getMidCategory().equals(midCategoryBox.getValue())).map(PoiCategory::getSubCategory).distinct().collect(Collectors.toList());
            subCategoryBox.getItems().remove(0, subCategoryBox.getItems().size());
            subCategoryBox.getItems().addAll(subCategoryList);
            subCategoryBox.show();
        }
    }

    /**
     * 获取选中POI行业分类Code
     */
    public String getCategoryCode() {
        if (null != subCategoryBox.getValue()) {
            return poiCategoryList.stream().filter(e -> e.getSubCategory().equals(subCategoryBox.getValue())).map(PoiCategory::getCode).distinct().collect(Collectors.toList()).get(0);
        }
        if (null != midCategoryBox.getValue()) {
            return poiCategoryList.stream().filter(e -> e.getMidCategory().equals(midCategoryBox.getValue())).map(PoiCategory::getCode).distinct().collect(Collectors.toList()).get(0);
        }
        if (null != bigCategoryBox.getValue()) {
            return poiCategoryList.stream().filter(e -> e.getBigCategory().equals(bigCategoryBox.getValue())).map(PoiCategory::getCode).distinct().collect(Collectors.toList()).get(0);
        }
        return "";
    }

    /**
     * 查询下一级行政区（下拉框）
     *
     * @param mouseEvent 鼠标点击事件
     * @return void
     */
    public void searchNextDistrict(MouseEvent mouseEvent) {
        //当改变省份的时，城市和区县设置为null
        if (provincesBox.equals(mouseEvent.getSource())) {
            cityBox.setValue(null);
            countyBox.setValue(null);
            streetBox.setValue(null);
            //查询城市
        } else if (cityBox.equals(mouseEvent.getSource())) {
            if (null == provincesBox.getValue()) {
                messageTip("请先选择省份");
                return;
            }
            List<District> cityList = poiService.searchNextDistrict(provincesBox.getValue().getAdcode());
            cityBox.getItems().remove(0, cityBox.getItems().size());
            cityBox.getItems().addAll(cityList);
            //数据转换
            cityBox.setConverter(converter);
            countyBox.setValue(null);
            streetBox.setValue(null);
            cityBox.show();
            //查询区县
        } else if (countyBox.equals(mouseEvent.getSource())) {
            if (null == cityBox.getValue()) {
                messageTip("请先选择城市");
                return;
            }
            List<District> countyList = poiService.searchNextDistrict(cityBox.getValue().getAdcode());
            countyBox.getItems().remove(0, countyBox.getItems().size());
            countyBox.getItems().addAll(countyList);
            //数据转换
            countyBox.setConverter(converter);
            streetBox.setValue(null);
            countyBox.show();
            //查询乡镇
        } else {
            if (null == countyBox.getValue()) {
                messageTip("请先选择区县");
                return;
            }
            List<District> townList = poiService.searchNextDistrict(countyBox.getValue().getAdcode());
            streetBox.getItems().remove(0, streetBox.getItems().size());
            streetBox.getItems().addAll(townList);
            //数据转换
            streetBox.setConverter(converter);
            streetBox.show();
        }
    }

    /**
     * 查询行政区（省市区）POI
     *
     * @param actionEvent 触发事件
     * @return void
     */
    public void searchPoi(ActionEvent actionEvent) {
        String adcode = "";
        District district;
        //行政区边界经纬度
        String coordinates = null;
        String categoryCode = "";
        if (null != (district = streetBox.getValue())) {
            //街道对应的矩形区域
            coordinates = streetList.stream()
                    .filter(e -> e.getTown().equals(streetBox.getValue().getName()))
                    .filter(e -> e.getCountry().equals(countyBox.getValue().getName()))
                    .filter(e -> e.getCity().equals(cityBox.getValue().getName()))
                    .filter(e -> e.getProvince().equals(provincesBox.getValue().getName()))
                    .map(Street::getBorder)
                    .findFirst()
                    .orElseThrow(() -> new IllegalStateException("没有对应街道数据"));

        } else if (null != (district = countyBox.getValue())) {
            adcode = countyBox.getValue().getAdcode();
        } else if (null != (district = cityBox.getValue())) {
            adcode = cityBox.getValue().getAdcode();
        } else if (null != (district = provincesBox.getValue())) {
            adcode = provincesBox.getValue().getAdcode();
        }
        //省、市、县可以直接查边界数据
        if (null == streetBox.getValue()) {
            coordinates = poiService.searchCoordinates(adcode);
        }
        //官方说明当keywords和types为空的时候， 会默认指定types为120000（商务住宅）&150000（交通设施服务），所以要改为空时获取到所有的大类
        if ("".equals(keywords.getText()) && null == bigCategoryBox.getValue()) {
            categoryCode = "010000|020000|030000|040000|050000|060000|070000|080000|090000|100000|110000|120000|130000|140000|150000|160000|170000|180000|190000|200000";
        }

        clearMessage();
        messageTip("请稍等，正在查询...");
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //查询Poi
        List<Poi> pois = poiService.searchPoi(coordinates, district, keywords.getText(), categoryCode);
        //TODO：乡镇暂时按照区过滤,特殊处理
        if ("street".equals(district.getLevel())) {
            pois = pois.stream()
                    .filter(p -> p.getAdname().equals(countyBox.getValue().getName()))
                    .collect(Collectors.toList());
        }
        setTableData(pois);
        messageTip("已爬取完成，共POI: " + pois.size());
    }

    /**
     * 导出Poi
     *
     * @return void
     */
    public void exportPoi() {
        this.poiService.exportPoi();
        messageTip("POI已导出Excel");
    }

    /**
     * 设置表格数据
     *
     * @param pois Poi数据集
     * @return void
     */
    public void setTableData(List<Poi> pois) {
        colNum.setCellFactory(new IDCell<>());
        colName.setCellValueFactory(new PropertyValueFactory<>("name"));
        colPname.setCellValueFactory(new PropertyValueFactory<>("pname"));
        colCityname.setCellValueFactory(new PropertyValueFactory<>("cityname"));
        colAdname.setCellValueFactory(new PropertyValueFactory<>("adname"));
        colAddress.setCellValueFactory(new PropertyValueFactory<>("address"));
        colAlias.setCellValueFactory(new PropertyValueFactory<>("alias"));
        colTel.setCellValueFactory(new PropertyValueFactory<>("tel"));
        colLocation.setCellValueFactory(new PropertyValueFactory<>("location"));
        colId.setCellValueFactory(new PropertyValueFactory<>("id"));
        colTag.setCellValueFactory(new PropertyValueFactory<>("tag"));
        colPcode.setCellValueFactory(new PropertyValueFactory<>("pcode"));
        colType.setCellValueFactory(new PropertyValueFactory<>("type"));
        colTypecode.setCellValueFactory(new PropertyValueFactory<>("typecode"));
        colCitycode.setCellValueFactory(new PropertyValueFactory<>("citycode"));
        colWebsite.setCellValueFactory(new PropertyValueFactory<>("website"));
        colEmail.setCellValueFactory(new PropertyValueFactory<>("email"));
        colAdcode.setCellValueFactory(new PropertyValueFactory<>("adcode"));
        colGridcode.setCellValueFactory(new PropertyValueFactory<>("gridcode"));
        colEntrLocation.setCellValueFactory(new PropertyValueFactory<>("entr_location"));
        colExitLocation.setCellValueFactory(new PropertyValueFactory<>("exit_location"));
        ObservableList<Poi> data = FXCollections.observableArrayList(pois);
        tableView.setEditable(true);
        tableView.setItems(data);
    }

    /**
     * 消息提示
     *
     * @param message 提示信息
     * @return void
     */
    public void messageTip(String message) {
        this.messageDetail.appendText(message + "\r\n");
    }

    /**
     * 清空消息
     *
     * @return void
     */
    public void clearMessage() {
        this.messageDetail.clear();
    }
}